import { Directive, DirectiveBinding, watchEffect,watch } from "vue";
import { debounce } from "@/utils/debounce";


/**
 * 类型校验
 */
interface DebounceOptions {
  fn: (...args: any[])=> any;
  event: string | string[];
  delay?: number;
}
/**
 * 拓展HtmlElement,避免ts类型检查报错
 */
interface MyHTMLElement extends HTMLElement{
  __debouncedEvents__?: Array<{ eventType: string; handler: (...args: any[])=> any;}> // 使用具体的函数类型 ;
  __stopDebounceWatch__?: () => void;
}

/**
 * Vue 自定义指令，提供防抖功能。
 *
 * 使用方法：
 * 在元素上应用 v-debounce 指令，并传入一个对象，该对象包含：
 * - fn: 需要防抖的函数。
 * - event: 触发防抖的事件类型，可以是一个字符串或字符串数组。
 * - delay (可选): 防抖延迟时间，单位毫秒，默认为 500 毫秒。
 *
 * 示例：
 * <button v-debounce="{ fn: handleClick, event: ['click', 'mouseover'], delay: 300 }">Click me</button>
 */
const vDebounce: Directive = {
  mounted(el: MyHTMLElement, binding: DirectiveBinding<DebounceOptions>) {
    // 使用 watch 来监听 binding.value 的变化
    
    
    const stopWatch = watch(
      () => binding.value,
      (value) => {
     
        if (!value || typeof value.fn !== "function" || !value.event) {
          console.warn(
            'vDebounce expects an object with "fn" and "event" properties'
          );
          return;
        }

        const { fn, event, delay = 500 } = value;

        // 移除之前的防抖监听
        removeDebounceListeners(el);

        const events = Array.isArray(event) ? event : [event];
        el.__debouncedEvents__ = events.map((eventType) => {
          const debouncedFn = debounce(fn, delay).debouncedFn;
          el.addEventListener(eventType, debouncedFn);
          return { eventType, handler: debouncedFn };
        });
      },
      { immediate: true ,deep: true}/* immediate: 首次绑定时，是否以当前的初始值执行一次 watch 中的函数 ,deep:对象内部属性深度监听,否则只有创建新对象赋值时才能监听到*/
    );

    el.__stopDebounceWatch__ = stopWatch;
  },
  beforeUnmount(el: MyHTMLElement) {
    removeDebounceListeners(el);
    if (el.__stopDebounceWatch__) {
      el.__stopDebounceWatch__();
    }
  },
};

/**
 * 移除元素上所有防抖事件监听器。
 *
 *
 * @param {MyHTMLElement} el - 绑定指令的 DOM 元素。
 */
function removeDebounceListeners(el: MyHTMLElement) {
  if (el.__debouncedEvents__) {
    el.__debouncedEvents__.forEach(({ eventType, handler }) => {
      el.removeEventListener(eventType, handler);
    });
    // 清除存储的事件监听器信息
    delete el.__debouncedEvents__;
  }
}

export default vDebounce;
